package org.convallaria.framework.security.util;

import jakarta.servlet.http.HttpServletRequest;
import org.convallaria.framework.security.core.SecurityUser;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Optional;

/**
 * Security工具类
 * 提供获取当前用户、权限校验等功能
 * 
 * @author convallaria
 * @since 1.0.0
 */
public class SecurityUtils {

    private SecurityUtils() {
        throw new IllegalStateException("Utility class");
    }

    /**
     * 获取当前登录用户
     * 
     * @return 当前用户信息
     */
    public static SecurityUser getCurrentUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.isAuthenticated() 
                && authentication.getPrincipal() instanceof SecurityUser) {
            return (SecurityUser) authentication.getPrincipal();
        }
        return null;
    }

    /**
     * 获取当前用户ID
     * 
     * @return 用户ID
     */
    public static Long getCurrentUserId() {
        SecurityUser user = getCurrentUser();
        return user != null ? user.getUserId() : null;
    }

    /**
     * 获取当前用户名
     * 
     * @return 用户名
     */
    public static String getCurrentUsername() {
        SecurityUser user = getCurrentUser();
        return user != null ? user.getUsername() : null;
    }

    /**
     * 获取当前租户ID
     * 
     * @return 租户ID
     */
    public static Long getCurrentTenantId() {
        SecurityUser user = getCurrentUser();
        return user != null ? user.getTenantId() : null;
    }

    /**
     * 获取当前部门ID
     * 
     * @return 部门ID
     */
    public static Long getCurrentDeptId() {
        SecurityUser user = getCurrentUser();
        return user != null ? user.getDeptId() : null;
    }

    /**
     * 判断用户是否已登录
     * 
     * @return 是否已登录
     */
    public static boolean isAuthenticated() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return authentication != null && authentication.isAuthenticated() 
                && authentication.getPrincipal() instanceof SecurityUser;
    }

    /**
     * 判断是否有指定权限
     * 
     * @param permission 权限标识
     * @return 是否有权限
     */
    public static boolean hasPermission(String permission) {
        if (permission == null || permission.trim().isEmpty()) {
            return false;
        }
        SecurityUser user = getCurrentUser();
        return user != null && user.getPermissions() != null 
                && user.getPermissions().contains(permission);
    }

    /**
     * 判断是否有任一权限
     * 
     * @param permissions 权限标识数组
     * @return 是否有权限
     */
    public static boolean hasAnyPermission(String... permissions) {
        if (permissions == null || permissions.length == 0) {
            return false;
        }
        SecurityUser user = getCurrentUser();
        if (user == null || user.getPermissions() == null) {
            return false;
        }
        for (String permission : permissions) {
            if (user.getPermissions().contains(permission)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断是否有所有权限
     * 
     * @param permissions 权限标识数组
     * @return 是否有权限
     */
    public static boolean hasAllPermissions(String... permissions) {
        if (permissions == null || permissions.length == 0) {
            return true;
        }
        SecurityUser user = getCurrentUser();
        if (user == null || user.getPermissions() == null) {
            return false;
        }
        for (String permission : permissions) {
            if (!user.getPermissions().contains(permission)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 判断是否有指定角色
     * 
     * @param role 角色标识
     * @return 是否有角色
     */
    public static boolean hasRole(String role) {
        if (role == null || role.trim().isEmpty()) {
            return false;
        }
        SecurityUser user = getCurrentUser();
        return user != null && user.getRoles() != null 
                && user.getRoles().contains(role);
    }

    /**
     * 判断是否有任一角色
     * 
     * @param roles 角色标识数组
     * @return 是否有角色
     */
    public static boolean hasAnyRole(String... roles) {
        if (roles == null || roles.length == 0) {
            return false;
        }
        SecurityUser user = getCurrentUser();
        if (user == null || user.getRoles() == null) {
            return false;
        }
        for (String role : roles) {
            if (user.getRoles().contains(role)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取请求Token
     * 
     * @param request HTTP请求
     * @param header Token请求头名称
     * @param prefix Token前缀
     * @return Token
     */
    public static String getToken(HttpServletRequest request, String header, String prefix) {
        String token = request.getHeader(header);
        if (token != null && !token.trim().isEmpty() && token.startsWith(prefix)) {
            return token.substring(prefix.length());
        }
        return request.getParameter("token");
    }

    /**
     * 获取当前请求
     * 
     * @return HttpServletRequest
     */
    public static Optional<HttpServletRequest> getCurrentRequest() {
        return Optional.ofNullable(RequestContextHolder.getRequestAttributes())
                .filter(ServletRequestAttributes.class::isInstance)
                .map(ServletRequestAttributes.class::cast)
                .map(ServletRequestAttributes::getRequest);
    }

    /**
     * 获取请求IP
     * 
     * @return IP地址
     */
    public static String getRequestIp() {
        return getCurrentRequest()
                .map(request -> {
                    String ip = request.getHeader("X-Forwarded-For");
                    if (ip == null || ip.trim().isEmpty() || "unknown".equalsIgnoreCase(ip)) {
                        ip = request.getHeader("Proxy-Client-IP");
                    }
                    if (ip == null || ip.trim().isEmpty() || "unknown".equalsIgnoreCase(ip)) {
                        ip = request.getHeader("WL-Proxy-Client-IP");
                    }
                    if (ip == null || ip.trim().isEmpty() || "unknown".equalsIgnoreCase(ip)) {
                        ip = request.getRemoteAddr();
                    }
                    return ip;
                })
                .orElse("unknown");
    }
}
